package cn.lwalan.commonUtils;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class DefaultSequence {

    private final Lock lock = new ReentrantLock();
    private SequenceDao sequenceDao;
    private ConcurrentHashMap<String,SequenceRange> sequenceRangeMap = new ConcurrentHashMap<>();
//    private volatile SequenceRange currentRange;

    public DefaultSequence() {
    }

    public long nextValue(String name) throws Exception {
        SequenceRange currentRange = sequenceRangeMap.get(name);
        if (currentRange == null) {
            this.lock.lock();

            try {
                if (currentRange == null) {
                    currentRange = this.sequenceDao.nextRange(name);
                    sequenceRangeMap.put(name,currentRange);
                }
            } finally {
                this.lock.unlock();
            }
        }

        long value = currentRange.getAndIncrement();
        if (value == -1L) {
            this.lock.lock();

            try {
                do {
                    if (currentRange.isOver()) {
                        currentRange = this.sequenceDao.nextRange(name);
                    }
                    value = currentRange.getAndIncrement();
                } while(value == -1L);
            } finally {
                this.lock.unlock();
            }
        }

        if (value < 0L) {
            throw new Exception("Sequence value overflow, value = " + value);
        } else {
            return value;
        }
    }

    public SequenceDao getSequenceDao() {
        return this.sequenceDao;
    }

    public void setSequenceDao(SequenceDao sequenceDao) {
        this.sequenceDao = sequenceDao;
    }


}
